package com.sk.ccflower.server.lib.dbUtils.sql;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;

import org.apache.log4j.Logger;

public abstract class BaseSql
{
	protected	Class<?>			m_beanCls = null;
	protected	Logger 				m_log = null;

	// m_arr
	//
	public 	ArrayList<Object>		m_arr = null;

	// m_hash
	//
	public HashMap<String, Object>	m_hash = null;
	protected ArrayList<String>		m_keyFieldName = null;
	protected Field[]				m_keyField = null;

	//
	//
	public BaseSql (Class<?> _beanCls, String ..._keyFieldNames) throws Exception
	{
		//
		m_log		= Logger.getLogger(getClass());

		//
		m_beanCls = _beanCls;

		m_arr = new ArrayList<Object>();
    	m_hash = new HashMap<String, Object>();

		// Key Field 생성
		//
		initKeyFields(_keyFieldNames);
	}

	private void initKeyFields(String ..._keyFieldNames) throws Exception
	{
		// m_hash의 Key Field 생성
		//
		if (m_keyFieldName == null && _keyFieldNames.length > 0)
		{
			m_keyFieldName = new ArrayList<String>(_keyFieldNames.length);
			for(String name : _keyFieldNames)
			{
				m_keyFieldName.add(name);
			}

			m_keyField = getKeyField(m_keyFieldName);
		}

		// 하위 클래스의 Key Field 생성
		//
		initKeyFields();
	}

	public void clear ()
	{
		if (m_arr!=null) m_arr.clear();
		if (m_hash!=null) m_hash.clear();

		clearOtherHash();
	}

	protected Field[] getKeyField(ArrayList<String> _keyFieldNames) throws Exception
	{
		Field[] fieldBean = m_beanCls.getFields();

		Field[] keyField 	= null;

		try
		{
			keyField 	= new Field[_keyFieldNames.size()];

			int n = _keyFieldNames.size();
			int nAllField = fieldBean.length;

			int i=0;
			int j=0;
			for(i=0; i<n; i++)
			{
				for(j=0; j<nAllField; j++)
				{
					if(_keyFieldNames.get(i).toLowerCase().equals(fieldBean[j].getName().toLowerCase()))
					{
						keyField[i] = fieldBean[j];
						break;
					}
				}

				// 오류! 필드 명  찾을 수 없음
				//
				if (j==nAllField)
				{
					throw new Exception( "KeyField 불일치 : " +_keyFieldNames.get(i) );
				}
			}
		}
		catch (Exception e)
		{
			throw e;
		}

		return keyField;
	}

	public int	size()
	{
		return m_arr != null ? m_arr.size():0;
	}

	// getKey() =======================================================================================
    /**
     * 	m_hash의 Key 생성
     */
	public String getKeyByObj(Object _data)
	{
		return m_keyField==null ? null : getKeyByObj(_data, m_keyField);
	}

	/**
	 * 	주어진 _keyField로 부터 Key생성
	 */
	public String getKeyByObj(Object _data, Field[] _keyField)
	{
		StringBuffer sb = null;

		try
		{
			for (int i=0; i<_keyField.length; i++)
			{
				if (sb==null) sb = new StringBuffer();
				else sb.append("|");

				sb.append(_keyField[i].get(_data) == null?"":_keyField[i].get(_data).toString());
			}
		}
		catch (Exception e)
		{
			sb = null;
		}

		return sb == null ? null : sb.toString();
	}

	/**
	 * 	Key에 해당하는 값을 입력하여 Key 생성
	 */
	public String getKey(String ..._keyValues)
	{
		if (_keyValues.length == 0) return null;

		StringBuffer sb = null;

		try
		{
			for (String val : _keyValues)
			{
				if (sb==null) sb = new StringBuffer();
				else sb.append("|");

				sb.append(val);
			}
		}
		catch (Exception e)
		{
			sb = null;
		}

		return sb == null ? null : sb.toString();
	}

	// get() =======================================================================================
	//
    /**
     * 	m_hash에서 검색
     */
	public Object get(String _key)
	{
		return m_hash==null ? null : get(_key, m_hash);
	}

	/**
	 *	주어진 _hash에서 검색
	 */
	public Object get(String _key, HashMap<String, Object> _hash)
	{
		return _hash.get(_key);
	}

	/**
	 * m_hash에서 입력되는 object의 m_keyField와 같은 key값을 갖는 Object를 찾음
	 */
	public Object getByObj(Object _obj)
	{
		return m_hash==null ? null : getByObj(_obj, m_hash, m_keyField);
	}

	/**
	 * m_hash에서 입력되는 object의 _keyField와 같은 key값을 갖는 Object를 찾음
	 */
	public Object getByObj(Object _obj,  Field[] _keyField)
	{
		return getByObj(_obj, m_hash, _keyField);
	}

	/**
	 * 입력되는 _hash에서 입력되는 object의 m_keyField와 같은 key값을 갖는 Object를 찾음
	 */
	public Object getByObj(Object _obj, HashMap<String, Object> _hash)
	{
		return getByObj(_obj, _hash, m_keyField);
	}

	/**
	 * 입력되는 _hash에서 입력되는 object의 _keyField와 같은 key값을 갖는 Object를 찾음
	 */
	public Object getByObj(Object _obj, HashMap<String, Object> _hash, Field[] _keyFields)
	{
		return _hash != null?_hash.get(getKeyByObj(_obj, _keyFields)):null;
	}

	// put() =======================================================================================
	//
	/**
	 * _data를 m_keyField의 key를 이용하여 m_hash 및 m_arr에 등록
	 */
	public int put(Object _data) throws Exception
    {
		return put(_data, m_keyField);
    }

	/**
	 * _data를 _keyField의 key를 이용하여 m_hash 및 m_arr에 등록
	 */
	public int put(Object _data, Field[] _keField) throws Exception
	{
		// m_arr, m_hash
    	//
    	if (m_arr==null) m_arr = new ArrayList<Object>();
    	if (m_hash==null) m_hash = new HashMap<String, Object>();

    	//
		m_arr.add(_data);

		int res = put(_data, m_hash, _keField);

		// 하위 클래스에서 추가 정의된 hash에 데이터 등록
		//
		putInOtherHash (_data);

		return res;
	}

	/**
	 * _data를 m_keyField의 key를 이용하여 _hash에 추가
	 */
	public int put(Object _data, HashMap<String, Object> _hash) throws Exception
	{
		return put(_data, _hash, m_keyField);
	}

	/**
	 * _data를 _keyField의 key를 이용하여 _hash에 추가
	 */
	public int put(Object _data, HashMap<String, Object> _hash, Field[] _keyField) throws Exception
	{
		String key = getKeyByObj(_data, _keyField);
		if(key != null && _hash.get(key)==null) _hash.put(key, _data);
		else return 0;

		return 1;
	}

	/**
	 * 	_hash로부터  데이터 테이블 초기화
	 */
	public int put(HashMap<String, Object> _hash) throws Exception
    {
		// 버퍼 초기화
		//
    	clear();

    	// m_arr, m_hash
    	//
    	if (m_arr==null) m_arr = new ArrayList<Object>(_hash.size());
    	if (m_hash==null) m_hash = new HashMap<String, Object>(_hash.size());

    	Object obj;

    	Iterator<Object> it = _hash.values().iterator();
    	while( it.hasNext() )
    	{
    		obj = it.next();

    		m_arr.add(obj);
    		put(obj, m_hash, m_keyField);

    		// 하위 클래스에서 추가 정의된 hash에 데이터 등록
    		//
    		putInOtherHash (obj);
    	}

    	return m_hash.size();
    }

	/**
	 * 	_arr로부터 데이터 테이블 초기화
	 */
	public int put(ArrayList<Object> _arr) throws Exception
    {
		// 버퍼 초기화
		//
    	clear();

    	// m_arr, m_hash
    	//
    	m_arr = _arr;
    	if (m_hash==null) m_hash = new HashMap<String, Object>(m_arr.size());

    	for(int i=0; i<m_arr.size(); i++)
    	{
    		put(m_arr.get(i), m_hash, m_keyField);

    		// 하위 클래스에서 추가 정의된 hash에 데이터 등록
    		//
    		putInOtherHash (m_arr.get(i));
    	}

    	return m_arr.size();
    }

	/**
	 * 	_arr로부터 데이터 테이블 초기화
	 */
	public int put(Object[] _arr) throws Exception
    {
		// 버퍼 초기화
		//
    	clear();

    	// m_arr, m_hash
    	//
    	for(int i=0; i<_arr.length; i++)
    	{
    		put (_arr[i]);
    	}

    	return _arr.length;
    }

	public static String[] getColumn(String _column)
	{
		String [] cols = _column.split(",");
		for( int i = 0 ; i < cols.length ; i++) cols[i] = cols[i].trim();
		return cols;
	}

	public static String makeInsertSql(String _tablename, String _columns, String ..._appendColumn)
	{
		String[] cols = getColumn(_columns);

		StringBuffer sb = new StringBuffer();

		sb.append("INSERT INTO ");
		sb.append(_tablename);
		sb.append(" (").append(_columns);
		for(String col : _appendColumn) sb.append(",").append(col);
		sb.append(")").append(" VALUES (");

		for(int i=0; i<cols.length; i++) {
			if(i!=0) sb.append(",");
			sb.append("?");
		}

		for(int i=0; i<_appendColumn.length; i++) {
			sb.append(",?");
		}

		sb.append(")");

		return sb.toString();
	}

	public static String makeUpdateSql(String _tablename, String _columns, String ..._appendColumn)
	{
		String[] cols = getColumn(_columns);

		StringBuffer sb = new StringBuffer();

		sb.append("UPDATE ");
		sb.append(_tablename);
		sb.append(" SET ");

		for(int i=0; i<cols.length; i++) {
			if(i!=0) sb.append(",");
			sb.append(cols[i]).append("=").append("?");
		}

		for(String col : _appendColumn) {
			sb.append(",").append(col).append("=").append("?");
		}

		sb.append(" WHERE ");

		return sb.toString();
	}

	public static String makeDeleteSql(String _tablename)
	{
		StringBuffer sb = new StringBuffer();

		sb.append("DELETE FROM ");
		sb.append(_tablename);
		sb.append(" WHERE ");

		return sb.toString();
	}

	/**
	 * 하위 클래스에서 hash를 추가한 경우 해당 hash를 clear하는 함수
	 */
	protected abstract void clearOtherHash();

	/**
	 * 	하위 클래스에서 hash를 추가 정의한 경우
	 * 	Key Field 생성 함수
	 *  this.initKeyFields(String ..._keyFieldNames)에서 호출됨
	 */
	protected abstract void initKeyFields() throws Exception;

	/**
	 * 	하위 클래스에서 hash를 추가 추가 정의한 경우
	 * 	put() 함수 호출시 추가 정의 된 hash에도 data를 등록하는 함수
	 * 	this.put() 함수들에서 호출됨
	 */
	protected abstract void putInOtherHash(Object _data) throws Exception;
}
